/**
 * Copyright (C) 2011 the author
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.linguamathematica.oa4j;

import java.util.List;
import java.util.Set;

import static java.lang.Double.parseDouble;
import static com.linguamathematica.oa4j.Base.newSet;

import com.linguamathematica.oa4j.Analysis.Decisiveness;
import com.linguamathematica.oa4j.Analysis.NER;
import com.linguamathematica.oa4j.Analysis.OfferingGuidance;
import com.linguamathematica.oa4j.Analysis.Polarity;
import com.linguamathematica.oa4j.Analysis.RequestingGuidance;
import com.linguamathematica.oa4j.Analysis.Temporality;
import com.linguamathematica.oa4j.DemographicsAnalysis.Age;
import com.linguamathematica.oa4j.DemographicsAnalysis.Education;
import com.linguamathematica.oa4j.DemographicsAnalysis.Gender;
import com.linguamathematica.oa4j.DemographicsAnalysis.Language;
import com.linguamathematica.oa4j.StylesAnalysis.Contrast;
import com.linguamathematica.oa4j.StylesAnalysis.Flamboyance;
import com.linguamathematica.oa4j.StylesAnalysis.Slang;
import com.linguamathematica.oa4j.TopicsAnalysis.Domain;
import com.linguamathematica.oa4j.TopicsAnalysis.Noun;
import com.linguamathematica.oa4j.schema.ActionResult;
import com.linguamathematica.oa4j.schema.ActionScorecard;
import com.linguamathematica.oa4j.schema.AmplifyScorecard;
import com.linguamathematica.oa4j.schema.ArrayOfResult;
import com.linguamathematica.oa4j.schema.DemographicsScorecard;
import com.linguamathematica.oa4j.schema.DomainResult;
import com.linguamathematica.oa4j.schema.PolarityResult;
import com.linguamathematica.oa4j.schema.Result;
import com.linguamathematica.oa4j.schema.StyleScorecard;
import com.linguamathematica.oa4j.schema.TopicResult;
import com.linguamathematica.oa4j.schema.TopicScorecard;

/**
 * A factory for creating Analysis objects.
 */
class AnalysisFactory
{

	/**
	 * Actions analysis from.
	 * 
	 * @param response
	 *            the response
	 * @return the actions analysis
	 */
	ActionsAnalysis actionsAnalysisFrom(final ActionScorecard response)
	{
		final Set<ActionsAnalysis.Action> actions = newSet();

		for (final ActionResult item : response.getTopActions().getActionResult())
		{
			actions.add(new ActionsAnalysis.Action(//@formatter:off
					resultFrom(item.getAction()), 
					resultFrom(item.getDecisiveness(),Decisiveness.class),
					resultFrom(item.getOfferingGuidance(),OfferingGuidance.class),
					resultFrom(item.getRequestingGuidance(),RequestingGuidance.class),
					resultFrom(item.getActionType().getResult().get(0)),
					resultSetFrom(item.getTemporalityResult().getTemporality(),Temporality.class)));//@formatter:on
		}

		return new ActionsAnalysis(actions);
	}

	/**
	 * Analysis from.
	 * 
	 * @param response
	 *            the response
	 * @return the analysis
	 */
	Analysis analysisFrom(final AmplifyScorecard response)
	{
		return new Analysis( //@formatter:off
				demographicsAnalysisFrom(response.getDemographics()),
				styleAnalysisFrom(response.getStyles()),
				actionsAnalysisFrom(response.getActions()),
				topicsAnalysisFrom(response.getTopics()));//@formatter:on
	}

	/**
	 * Demographics analysis from.
	 * 
	 * @param demographics
	 *            the demographics
	 * @return the demographics analysis
	 */
	DemographicsAnalysis demographicsAnalysisFrom(final DemographicsScorecard demographics)
	{
		return new DemographicsAnalysis(//@formatter:off
				resultFrom(demographics.getAge(), Age.class), 
				resultFrom(demographics.getGender(), Gender.class), 
				resultFrom(demographics.getEducation(),	Education.class), 
				resultFrom(demographics.getLanguage(), Language.class));//@formatter:on
	}

	/**
	 * Domain from.
	 * 
	 * @param item
	 *            the item
	 * @return the topics analysis. domain
	 */
	TopicsAnalysis.Domain domainFrom(final DomainResult item)
	{
		final boolean noSubdomains = item.getSubdomains() == null;

		return new TopicsAnalysis.Domain(resultFrom(item.getDomain()), noSubdomains ? Domain.NULL : domainFrom(item
				.getSubdomains().getDomainResult().get(0)));
	}

	/**
	 * Domains from.
	 * 
	 * @param response
	 *            the response
	 * @return the sets the
	 */
	Set<TopicsAnalysis.Domain> domainsFrom(final List<DomainResult> response)
	{
		final Set<Domain> domains = newSet();

		for (final DomainResult item : response)
		{
			domains.add(domainFrom(item));
		}

		return domains;
	}

	/**
	 * Enum from.
	 * 
	 * @param <E>
	 *            the element type
	 * @param result
	 *            the result
	 * @param enumClass
	 *            the enum class
	 * @return the e
	 */
	<E extends Enum<E>> E enumFrom(final Result result, final Class<E> enumClass)
	{
		return Enum.valueOf(enumClass, result.getName().replaceAll(" |\\-", "_").toUpperCase());
	}

	/**
	 * Ner from.
	 * 
	 * @param response
	 *            the response
	 * @return the nER
	 */
	NER nerFrom(final ArrayOfResult response)
	{
		return response == null ? NER.NULL : new NER(response.getResult().get(0).getValue(), response.getResult()
				.get(1).getValue());
	}

	/**
	 * Polarity from.
	 * 
	 * @param response
	 *            the response
	 * @return the analysis. polarity result
	 */
	Analysis.PolarityResult polarityFrom(final PolarityResult response)
	{
		return new Analysis.PolarityResult(//@formatter:off
				resultFrom(response.getMin(), Polarity.class), 
				resultFrom(response.getMean(), Polarity.class),
				resultFrom(response.getMax(), Polarity.class));//@formatter:on
	}

	/**
	 * Proper nouns from.
	 * 
	 * @param response
	 *            the response
	 * @return the sets the
	 */
	Set<TopicsAnalysis.Noun> properNounsFrom(final List<TopicResult> response)
	{
		final Set<TopicsAnalysis.Noun> properNouns = newSet();

		for (final TopicResult item : response)
		{
			properNouns.add(new Noun(//@formatter:off
					resultFrom(item.getTopic()),
					polarityFrom(item.getPolarity() ),
					resultFrom(item.getOfferingGuidance(), OfferingGuidance.class),
					resultFrom(item.getRequestingGuidance(), RequestingGuidance.class), 
					nerFrom(item.getNamedEntityType())));//@formatter:on
		}

		return properNouns;
	}

	/**
	 * Result from.
	 * 
	 * @param response
	 *            the response
	 * @return the analysis. result
	 */
	Analysis.Result<String> resultFrom(final Result response)
	{
		return new Analysis.Result<String>(response.getName(), parseDouble(response.getValue()));
	}

	/**
	 * Result from.
	 * 
	 * @param <E>
	 *            the element type
	 * @param response
	 *            the response
	 * @param enumClass
	 *            the enum class
	 * @return the analysis. result
	 */
	<E extends Enum<E>> Analysis.Result<E> resultFrom(final Result response, final Class<E> enumClass)
	{
		return new Analysis.Result<E>(enumFrom(response, enumClass), parseDouble(response.getValue()));
	}

	/**
	 * Result set from.
	 * 
	 * @param response
	 *            the response
	 * @return the sets the
	 */
	Set<Analysis.Result<String>> resultSetFrom(final List<Result> response)
	{
		final Set<Analysis.Result<String>> results = newSet();

		for (final Result item : response)
		{
			results.add(resultFrom(item));
		}

		return results;
	}

	/**
	 * Result set from.
	 * 
	 * @param <E>
	 *            the element type
	 * @param response
	 *            the response
	 * @param enumClass
	 *            the enum class
	 * @return the sets the
	 */
	<E extends Enum<E>> Set<Analysis.Result<E>> resultSetFrom(final List<Result> response, final Class<E> enumClass)
	{
		final Set<Analysis.Result<E>> results = newSet();

		for (final Result item : response)
		{
			results.add(resultFrom(item, enumClass));
		}

		return results;
	}

	/**
	 * Style analysis from.
	 * 
	 * @param style
	 *            the style
	 * @return the styles analysis
	 */
	StylesAnalysis styleAnalysisFrom(final StyleScorecard style)
	{
		return new StylesAnalysis(//@formatter:off
				polarityFrom(style.getPolarity()), 
				resultFrom(style.getOfferingGuidance(),OfferingGuidance.class), 
				resultFrom(style.getRequestingGuidance(), RequestingGuidance.class),
				resultFrom(style.getDecisiveness(), Decisiveness.class),
				resultFrom(style.getSlang(), Slang.class),
				resultFrom(style.getFlamboyance(), Flamboyance.class),
				resultFrom(style.getContrast(), Contrast.class),
				resultSetFrom(style.getTemporalityResult().getTemporality(),Temporality.class));//@formatter:on
	}

	/**
	 * Topics analysis from.
	 * 
	 * @param topics
	 *            the topics
	 * @return the topics analysis
	 */
	TopicsAnalysis topicsAnalysisFrom(final TopicScorecard topics)
	{
		return new TopicsAnalysis(//@formatter:off
				properNounsFrom(topics.getProperNouns().getTopicResult()),
				topTopicsFrom(topics.getTopTopics().getTopicResult()),
				domainsFrom(topics.getDomains().getDomainResult()),
				resultSetFrom(topics.getLocations().getResult()));//@formatter:on
	}

	/**
	 * Top topics from.
	 * 
	 * @param response
	 *            the response
	 * @return the sets the
	 */
	Set<TopicsAnalysis.Noun> topTopicsFrom(final List<TopicResult> response)
	{
		return properNounsFrom(response);
	}
}
